package blingking.jfinal.orm.util;

import blingking.jfinal.orm.annotation.JFTable;
import com.jfinal.plugin.activerecord.Model;

import java.io.File;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author King
 * @description
 * @Date 2020/3/22
 */
public class PackageScanUtil {


    public static Set<Class> scanModelClasses(String[] packageNameArray, boolean isScanChildPackage) throws ClassNotFoundException {
        Set<Class> classes = new HashSet<>();
        for (String packageName : packageNameArray){
            scan(packageName, isScanChildPackage,classes);
        }
        Set<Class> modelClasses = classes
                .stream()
                .filter(clazz -> isJFinalModel(clazz))
                .collect(Collectors.toSet());
        return modelClasses;
    }


    private static Set<Class> scan(String packageName, boolean isScanChildPackage,Set<Class> classes) throws ClassNotFoundException {
        String packageDirName = packageName.replace(".", "/");
        URL url = Thread.currentThread().getContextClassLoader().getResource(packageDirName);
        if (url!=null){
            File targetFile = new File(url.getFile());
            if (!targetFile.exists() || targetFile.isFile()) {
                throw new RuntimeException(packageName + "不是一个包名或者该包名不存在");
            }
            getAllClass(targetFile, packageName, classes, isScanChildPackage);
        }
        return classes;
    }

    /**
     * 得到所有在parentFile目录下的class文件名称
     *
     * @param parentFile
     * @param classes
     * @param packageName
     */
    private static void getAllClass(File parentFile, String packageName, Collection<Class> classes, boolean isScanChildPath) throws ClassNotFoundException {

        File[] files = parentFile.listFiles();
        for (File file : files) {
            String path = file.getPath();
            if (file.isFile()) {

                if (path.endsWith(".class")) {
                    String className = packageName + "." +
                            path.substring(
                                    path.lastIndexOf('\\') + 1, path.lastIndexOf('.'));

                    Class clazz = Class.forName(className);

                    classes.add(clazz);
                }
            } else {
                if (isScanChildPath) {
                    String childBasePackageName = packageName + "." + path.substring(path.lastIndexOf('\\') + 1);
                    getAllClass(file, childBasePackageName, classes, isScanChildPath);
                }

            }
        }
    }

    private static boolean isJFinalModel(Class clazz){
        try {
            if (Modifier.isAbstract(clazz.getModifiers())){
                return false;
            }
            return clazz.isAnnotationPresent(JFTable.class)||(clazz.newInstance() instanceof Model);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

}
